package cn.jsj.onclock.service.impl;

import cn.jsj.onclock.dao.GroupDao;
import cn.jsj.onclock.dao.UserDao;
import cn.jsj.onclock.dao.UserJoinRequestDao;
import cn.jsj.onclock.exception.CustomException;
import cn.jsj.onclock.exception.CustomerErrorException;
import cn.jsj.onclock.pojo.GroupEnt;
import cn.jsj.onclock.pojo.UserEnt;
import cn.jsj.onclock.pojo.UserGroupInfo;
import cn.jsj.onclock.pojo.UserJoinRequest;
import cn.jsj.onclock.pojo.identity.ApproveResultEnum;
import cn.jsj.onclock.pojo.identity.GroupIdentityEnum;
import cn.jsj.onclock.pojo.identity.GroupJoinAuthEnum;
import cn.jsj.onclock.service.UserJoinRequestService;
import cn.jsj.onclock.socket.WebSocketManager;
import com.github.pagehelper.PageHelper;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.List;

/**
 * @author 卢斌
 */
@Slf4j
@Service
public class UserJoinRequestServiceImpl implements UserJoinRequestService {


    private final GroupDao groupDao;

    private final UserDao userDao;

    private final UserJoinRequestDao userJoinRequestDao;

    @Autowired
    public UserJoinRequestServiceImpl(UserJoinRequestDao userJoinRequestDao, GroupDao groupDao, UserDao userDao) {
        this.userJoinRequestDao = userJoinRequestDao;
        this.groupDao = groupDao;
        this.userDao = userDao;
    }


    /**
     * 用户提交个人加群申请
     *
     * @param userId    用户Id
     * @param groupId   目标群组
     * @param message   申请信息
     * @param leaveName 申请者留名
     * @return 提交加群申请后的状态（被拒绝，已加入，等待审核）
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApproveResultEnum submitUserJoinGroupRequest(Long userId, Long groupId, String message, String leaveName) {
        // 尝试获取目标群组信息
        GroupEnt groupEnt = groupDao.getGroupById(groupId);
        if (groupEnt == null) {
            throw new CustomException("您要申请加入的群组不存在");
        }
        // 尝试获取用户在目标群中的信息
        UserGroupInfo userGroupInfo = groupDao.getUserJoinGroupInfo(userId, groupId);
        if (userGroupInfo != null) {
            throw new CustomException("您已经在该群中，无需再次申请");
        }

        // 如果目标群组禁止用户提交加群申请
        if (GroupJoinAuthEnum.REFUSE.equals(groupEnt.getJoinAuth())) {
            return ApproveResultEnum.REJECTION;
        }

        // 组装加群申请信息实体
        UserJoinRequest insertBody = new UserJoinRequest();
        insertBody.setRequesterId(userId);
        insertBody.setAimGroup(groupId);
        insertBody.setMessage(message);
        // 判断用户有没有主动填写申请留名，如果没有填写则引用用户的姓名
        if (StringUtil.isNullOrEmpty(leaveName)) {
            UserEnt requestUser = userDao.getUserEntityById(userId);
            insertBody.setLeaveName(requestUser.getName());
        } else {
            insertBody.setLeaveName(leaveName);
        }

        // 申请信息插入数据库
        userJoinRequestDao.insertUserJoinRequestEntity(insertBody);

        // 如果目标群组默认同意用户的加群申请，则立刻让用户加群
        if (GroupJoinAuthEnum.ACQUIESCENCE.equals(groupEnt.getJoinAuth())) {
            // 将用户加群申请设置为已同意
            Integer influenceNumber = userJoinRequestDao.updateRequestResult(insertBody.getId(), 0L, ApproveResultEnum.PERMISSION);
            if (influenceNumber == 1) {
                return ApproveResultEnum.PERMISSION;
            }
            throw new CustomException("加群信息异常");
        }

        // 获取用户申请的目标群组中，有权限审批用户加群申请的负责人Id
        List<Long> checkUserIdList = listUserIdCouldCheckGroupJoinRequestInOneGroup(groupId);

        // 查询审批加群申请负责人中的在线用户，并将消息推送给他们
        for (Long one : checkUserIdList) {
            WebSocketSession session = WebSocketManager.get(one.toString());
            if (session != null) {
                try {
                    session.sendMessage(new TextMessage("groupRequest:" + groupId));
                } catch (IOException e) {
                    log.info("================ socket推送失败，用户可能刚刚离线 ================");
                }
            }
        }

        // 如果目标群组既不同意也不拒绝则等待（渣群）
        return ApproveResultEnum.WAITING;
    }


    /**
     * 用户获取和自己相关的群组申请记录
     *
     * @param userId   用户Id
     * @param result   申请结果
     * @param pageNum  页码号
     * @param pageSize 页容量
     * @return 用户相关的申请记录
     */
    @Override
    public List<UserJoinRequest> listUserJoinRequest(Long userId, ApproveResultEnum result, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        return userJoinRequestDao.listRequestByUserId(userId, result);
    }



    /**
     * 获取群组收到的加群申请信息
     *
     * @param userId   用户Id
     * @param groupId  群组Id
     * @param result   审批状态
     * @param pageNum  页码号
     * @param pageSize 页容量
     * @return 群组收到的加群申请
     */
    @Override
    public List<UserJoinRequest> listGroupReceivedUserJoinRequest(Long userId, Long groupId, ApproveResultEnum result, Integer pageNum, Integer pageSize) {
        UserGroupInfo userGroupInfo = groupDao.getUserJoinGroupInfo(groupId, userId);

        if (userGroupInfo == null) {
            throw new CustomException("您不在该群组中");
        }

        if (! GroupIdentityEnum.hasPowerOfCheckJoinGroupRequest(userGroupInfo.getRole())) {
            throw new CustomException("您不具有审核加群申请的权限");
        }
        PageHelper.startPage(pageNum, pageSize);
        return userJoinRequestDao.listRequestByGroupId(groupId, result);
    }



    /**
     * 群相关负责人审批普通用户提交的加群申请信息
     *
     * @param userId            审批者Id
     * @param userJoinRequestId 即将审批的用户申请
     * @param result            审批结果
     * @return 用户审批的结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApproveResultEnum judgeGroupRequest(Long userId, Long userJoinRequestId, ApproveResultEnum result) {

        // 负责人选择的审批结果只能为同意用户申请和不同意用户申请，如果选择等待则提示错误信息
        if (ApproveResultEnum.WAITING.equals(result)) {
            throw new CustomException("请选择有效的审批结果");
        }

        // 尝试获取该条加群申请，检查用户传入的参数是否真实
        UserJoinRequest joinRequest = userJoinRequestDao.getJoinRequestById(userJoinRequestId);
        if (joinRequest == null) {
            throw new CustomException("无法获取到该条申请");
        }

        // 检查该条加群申请是否已经审批过，只有未经过审批的申请才可以审批
        if (! ApproveResultEnum.WAITING.equals(joinRequest.getApproveResult())) {
            throw new CustomException("本条用户加群申请已经审批过");
        }

        // 检查用户是否在该群组中
        UserGroupInfo userGroupInfo = groupDao.getUserJoinGroupInfo(joinRequest.getAimGroup(), userId);
        if (userGroupInfo == null) {
            throw new CustomException("您不在该群组中");
        }

        // 如果用户在该群组中，再检查用户是否具有审批加群申请的角色权限
        if (GroupIdentityEnum.hasPowerOfCheckJoinGroupRequest(userGroupInfo.getRole())) {

            Integer influenceNumber = userJoinRequestDao.updateRequestResult(userJoinRequestId, userId, result);
            if (influenceNumber != 1) {
                throw new CustomerErrorException("群管理员审核用户的加群申请出现异常");
            }
        } else {
            throw new CustomException("您暂时没有审批权");
        }

        // 获取申请人的用户Id
        Long requestUserId = joinRequest.getRequesterId();
        WebSocketSession session = WebSocketManager.get(requestUserId.toString());
        if (session != null) {
            try {
                session.sendMessage(new TextMessage("requestGroupFinish:" + joinRequest.getAimGroup()));
            } catch (IOException e) {
                log.info("================ socket推送失败，用户可能刚刚离线 ================");
            }
        }
        return result;
    }

    /**
     * 获取群内具有审批其他用户加群申请权限的用户Id
     *
     * @param groupId 群组Id
     * @return 群内具有加群审批权限的用户Id列表
     */
    @Override
    public List<Long> listUserIdCouldCheckGroupJoinRequestInOneGroup(Long groupId) {
        List<GroupIdentityEnum> identities = GroupIdentityEnum.listIdentityCouldCheckJoinGroupRequest();
        if (identities.size() == 0) {
            throw new CustomException("无法获取群组内可审批加群申请的成员信息");
        }
        return userJoinRequestDao.listUserIdInGroupWithSpecialIdentity(groupId, identities);
    }

}
